/*********************************************************************
*
*      Copyright (C) 2002 Andrew Khan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***************************************************************************/

package org.nokatag.jxl.biff;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import org.nokatag.common.Assert;
import org.nokatag.jxl.write.biff.File;



/**
 * A container for the list of fonts used in this workbook
 */
public class Fonts
{
  /**
   * The list of fonts
   */
  private ArrayList fonts;

  /**
   * The default number of fonts
   */
  private static final int numDefaultFonts = 4;

  /**
   * Constructor
   */
  public Fonts()
  {
    fonts = new ArrayList();
  }

  /**
   * Adds a font record to this workbook.  If the FontRecord passed in has not
   * been initialized, then its font index is determined based upon the size
   * of the fonts list.  The FontRecord's initialized method is called, and
   * it is added to the list of fonts.
   *
   * @param f the font to add
   */
  public void addFont(FontRecord f)
  {
    if (!f.isInitialized())
    {
      int pos = fonts.size();

      // Remember that the pos with index 4 is skipped
      if (pos >= 4)
      {
        pos++;
      }

      f.initialize(pos);
      fonts.add(f);
    }
  }

  /**
   * Used by FormattingRecord for retrieving the fonts for the
   * hardcoded styles
   *
   * @param index the index of the font to return
   * @return the font with the specified font index
   */
  public FontRecord getFont(int index)
  {
    // remember to allow for the fact that font index 4 is not used
    if (index > 4)
    {
      index--;
    }

    return (FontRecord) fonts.get(index);
  }

  /**
   * Writes out the list of fonts
   *
   * @param outputFile the compound file to write the data to
   * @exception IOException
   */
  public void write(File outputFile) throws IOException
  {
    Iterator i = fonts.iterator();

    FontRecord font = null;
    while (i.hasNext())
    {
      font = (FontRecord) i.next();
      outputFile.write(font);
    }
  }

  /**
   * Rationalizes all the fonts, removing any duplicates
   *
   * @return the mappings between new indexes and old ones
   */
  IndexMapping rationalize()
  {
    IndexMapping mapping = new IndexMapping(fonts.size() + 1);
      // allow for skipping record 4

    ArrayList newfonts = new ArrayList();
    FontRecord fr = null;
    int numremoved = 0;

    // Preserve the default fonts
    for (int i = 0; i < numDefaultFonts; i++)
    {
      fr = (FontRecord) fonts.get(i);
      newfonts.add(fr);
      mapping.setMapping(fr.getFontIndex(), fr.getFontIndex());
    }

    // Now do the rest
    Iterator it = null;
    FontRecord fr2 = null;
    boolean duplicate = false;
    for (int i = numDefaultFonts; i < fonts.size(); i++)
    {
      fr = (FontRecord) fonts.get(i);

      // Compare to all the fonts currently on the list
      duplicate = false;
      it = newfonts.iterator();
      while (it.hasNext() && !duplicate)
      {
        fr2 = (FontRecord) it.next();
        if (fr.equals(fr2))
        {
          duplicate = true;
          mapping.setMapping(fr.getFontIndex(),
                             mapping.getNewIndex(fr2.getFontIndex()));
          numremoved++;
        }
      }

      if (!duplicate)
      {
        // Add to the new list
        newfonts.add(fr);
        int newindex = fr.getFontIndex() - numremoved;
        Assert.verify(newindex > 4);
        mapping.setMapping(fr.getFontIndex(), newindex);
      }
    }

    // Iterate through the remaining fonts, updating all the font indices
    it = newfonts.iterator();
    while (it.hasNext())
    {
      fr = (FontRecord) it.next();
      fr.initialize(mapping.getNewIndex(fr.getFontIndex()));
    }

    fonts = newfonts;

    return mapping;
  }
}
